/*
三条消除规则
    编译器使用三条消除规则来确定哪些场景不需要显式地去标注生命周期。其中第一条规则应用在输入生命周期上，第二、三条应用在输出生命周期上。若编译器发现三条规则都不适用时，就会报错，提示你需要手动标注生命周期。
    每一个引用参数都会获得独自的生命周期
        例如一个引用参数的函数就有一个生命周期标注: fn foo<'a>(x: &'a i32)，两个引用参数的有两个生命周期标注:fn foo<'a, 'b>(x: &'a i32, y: &'b i32), 依此类推。
    若只有一个输入生命周期(函数参数中只有一个引用类型)，那么该生命周期会被赋给所有的输出生命周期，也就是所有返回值的生命周期都等于该输入生命周期
        例如函数 fn foo(x: &i32) -> &i32，x 参数的生命周期会被自动赋给返回值 &i32，因此该函数等同于 fn foo<'a>(x: &'a i32) -> &'a i32
    若存在多个输入生命周期，且其中一个是 &self 或 &mut self，则 &self 的生命周期被赋给所有的输出生命周期
        拥有 &self 形式的参数，说明该函数是一个 方法，该规则让方法的使用便利度大幅提升。
        */

/*
例子 1

fn first_word(s: &str) -> &str { // 实际项目中的手写代码
首先，我们手写的代码如上所示时，编译器会先应用第一条规则，为每个参数标注一个生命周期：

fn first_word<'a>(s: &'a str) -> &str { // 编译器自动为参数添加生命周期
此时，第二条规则就可以进行应用，因为函数只有一个输入生命周期，因此该生命周期会被赋予所有的输出生命周期：

fn first_word<'a>(s: &'a str) -> &'a str { // 编译器自动为返回值添加生命周期
此时，编译器为函数签名中的所有引用都自动添加了具体的生命周期，因此编译通过，且用户无需手动去标注生命周期，只要按照 fn first_word(s: &str) -> &str { 的形式写代码即可。

例子 2 再来看一个例子：

fn longest(x: &str, y: &str) -> &str { // 实际项目中的手写代码
首先，编译器会应用第一条规则，为每个参数都标注生命周期：

fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str {
但是此时，第二条规则却无法被使用，因为输入生命周期有两个，第三条规则也不符合，因为它是函数，不是方法，因此没有 &self 参数。在套用所有规则后，编译器依然无法为返回值标注合适的生命周期，因此，编译器就会报错，提示我们需要手动标注生命周期：

*/
